package com.feather.tenia.oracle;

import com.feather.common.data.DataTable;
import com.feather.common.data.simple.SimpleColumn;
import com.feather.common.db.Connector;
import com.feather.tenia.adapter.TeniaAdapter;
import com.feather.tenia.oracle.fetcher.BLOB_Fetcher;
import com.feather.tenia.oracle.fetcher.CLOB_Fetcher;
import com.feather.tenia.oracle.fetcher.CURSOR_Fetcher;
import com.feather.tenia.oracle.fetcher.REFCURSOR_Fetcher;
import com.feather.tenia.oracle.saver.String_BLOB;
import com.feather.tenia.oracle.saver.String_CLOB;
import com.feather.tenia.oracle.saver.byteArray_BLOB;
import com.feather.tenia.oracle.saver.byteArray_CLOB;
import com.feather.tenia.JdbcProperty;
import com.feather.tenia.Procedure;
import com.feather.tenia.ProcedureMeta;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;

/**
 * @author flogyin
 */
public class OracleTenia extends TeniaAdapter {
	// public static final String SCHEMA_MARK = "~";
	public static final String	DT_VARCHAR2		= "VARCHAR2";
	public static final String	DT_REF_CURSOR	= "REF CURSOR";

	protected CURSOR_Fetcher	cursorFetcher;

	public OracleTenia(Connector connector, JdbcProperty jdbcProperty) {
		super(connector, jdbcProperty);

		this.cursorFetcher = new CURSOR_Fetcher(this);

		// [DbFetcher]
		super.typeMapping.register(new BLOB_Fetcher());// OracleTypes.BLOB
		super.typeMapping.register(new CLOB_Fetcher());// OracleTypes.CLOB
		super.typeMapping.register(this.cursorFetcher);// OracleTypes.CURSOR
		super.typeMapping.register(new REFCURSOR_Fetcher(this));// OracleTypes.CURSOR

		// [DbSaver]
		super.typeMapping.register(new byteArray_BLOB());// byte[] ->
															// OracleTypes.BLOB
		super.typeMapping.register(new String_CLOB());// String ->
														// OracleTypes.CLOB
		super.typeMapping.register(new byteArray_CLOB());// byte[] ->
															// OracleTypes.CLOB
		super.typeMapping.register(new String_BLOB());// String ->
														// OracleTypes.BLOB

		mapSqlType(DT_VARCHAR2, oracle.jdbc.OracleTypes.VARCHAR);// 12
		mapSqlType(DT_REF_CURSOR, oracle.jdbc.OracleTypes.CURSOR);// -10
		mapSqlType("LONGVARCHAR", oracle.jdbc.OracleTypes.LONGVARCHAR);// -1
		// mapSqlType("TIMESTAMPNS",
		// oracle.jdbc.OracleTypes.TIMESTAMPNS);//-100(deprecated)
		mapSqlType("TIMESTAMPTZ", oracle.jdbc.OracleTypes.TIMESTAMPTZ);// -101
		mapSqlType("TIMESTAMPLTZ", oracle.jdbc.OracleTypes.TIMESTAMPLTZ);// -102
		mapSqlType("INTERVALYM", oracle.jdbc.OracleTypes.INTERVALYM);// -103
		mapSqlType("INTERVALDS", oracle.jdbc.OracleTypes.INTERVALDS);// -104
		mapSqlType("BFILE", oracle.jdbc.OracleTypes.BFILE);// 2006
		mapSqlType("OPAQUE", oracle.jdbc.OracleTypes.OPAQUE);// 2007
		mapSqlType("JAVA_STRUCT", oracle.jdbc.OracleTypes.JAVA_STRUCT);// 2008
		mapSqlType("PLSQL_INDEX_TABLE", oracle.jdbc.OracleTypes.PLSQL_INDEX_TABLE);// -14
		mapSqlType("NUMBER", oracle.jdbc.OracleTypes.NUMBER);// 2
		mapSqlType("RAW", oracle.jdbc.OracleTypes.RAW);// -2
		mapSqlType("FIXED_CHAR", oracle.jdbc.OracleTypes.FIXED_CHAR);// 999
	}

	@Override
	public Procedure getProcedure(String procName) throws SQLException {
		Procedure procedure = super.procedureCache.get(procName);
		if (procedure == null) {
			ProcedureMeta meta = this.createProcedureMeta(procName);
			List<ProcedureMeta> metaList = super.listProcedure(meta.getCatalog(), meta.getSchema(), meta.getName());
			if (metaList.size() > 0) {
				meta = metaList.get(0);
				meta.setOriginal(procName);
				procedure = new OracleProcedure(this, meta);
				if (isCacheProcedureColumn())
					super.procedureCache.put(procName, procedure);
			}
		}
		return procedure;
	}

	@Override
	public Procedure getProcedure(String catalog, String schema, String name) throws SQLException {
		String procName = catalog + "." + schema + "." + name;
		Procedure procedure = super.procedureCache.get(procName);
		if (procedure == null) {
			List<ProcedureMeta> metaList = super.listProcedure(catalog, schema, name);
			if (metaList.size() == 1) {
				ProcedureMeta meta = metaList.get(0);
				procedure = new OracleProcedure(this, meta);
				if (isCacheProcedureColumn())
					super.procedureCache.put(procName, procedure);
			}
		}
		return procedure;
	}

	@Override
	protected void setCatalog() {
		// PKG Head
	}

	@Override
	protected void setSchema() {
		super.schema = super.jdbcProperty.getUserName();
	}

	@Override
	protected ProcedureMeta createProcedureMeta() {
		return createProcedureMeta(super.catalog, super.schema, null);
	}

	@Override
	protected ProcedureMeta createProcedureMeta(String procName) {
		String catalog = null;// PKG Head
		String schema = super.schema;// User Name
		String name = procName;
		if (name != null && name.indexOf('"') == -1) {
			name = name.trim().toUpperCase();
			String[] array = name.split("\\.");
			switch (array.length) {
				case 1: {
					break;
				}
				case 2: {
					// PackageName.procName
					catalog = array[0].trim();
					name = array[1].trim();
					break;
				}
			}
		}
		ProcedureMeta meta = createProcedureMeta(catalog, schema, name);
		meta.setOriginal(procName);
		return meta;
	}

	@Override
	protected ProcedureMeta createProcedureMeta(String catalog, String schema, String name) {
		OracleProcedureMeta meta = new OracleProcedureMeta();
		meta.setCatalog(catalog);
		meta.setSchema(schema);
		meta.setName(name);
		return meta;
	}

	@Override
	protected DataTable getDataTable(Statement statement, ResultSet resultSet) throws SQLException {
		SimpleColumn column = new SimpleColumn();
		DataTable dataTable = (DataTable) this.cursorFetcher.fetch(resultSet, column);
		return dataTable;
	}
}

/*
 * StringBuilder builder = new StringBuilder();
 * builder.append("SELECT package_name AS procedure_cat, ");
 * builder.append("       owner AS procedure_schem, ");
 * builder.append("       object_name AS procedure_name, ");
 * builder.append("       argument_name AS column_name, ");
 * builder.append("       DECODE(position, 0, 5, ");
 * builder.append("                        DECODE(in_out, 'IN', 1, ");
 * builder.append("                                       'OUT', 4, ");
 * builder.append("                                       'IN/OUT', 2, ");
 * builder
 * .append("                                       0)) AS column_type, ");
 * builder.append("       DECODE (data_type, 'BIT', -7, ");
 * builder.append("                          'TINYINT', -6, ");
 * builder.append("                          'SMALLINT', 5, ");
 * builder.append("                          'INTEGER', 4, ");
 * builder.append("                          'BIGINT', -5, ");
 * builder.append("                          'FLOAT', 6, ");
 * builder.append("                          'REAL', 7, ");
 * builder.append("                          'DOUBLE', 8, ");
 * builder.append("                          'NUMERIC', 2, ");
 * builder.append("                          'DECIMAL', 3, ");
 * builder.append("                          'CHAR', 1, ");
 * builder.append("                          'VARCHAR2', 12, ");
 * builder.append("                          'LONGVARCHAR', -1, ");
 * builder.append("                          'DATE', 91, ");
 * builder.append("                          'TIME', 92, ");
 * builder.append("                          'TIMESTAMP', 93, ");
 * 
 * builder.append("                          'TIMESTAMPNS', -100, ");//@deprecated
 * builder.append("                          'TIMESTAMPTZ', -101, ");
 * builder.append("                          'TIMESTAMPLTZ', -102, ");
 * builder.append("                          'INTERVALYM', -103, ");
 * builder.append("                          'INTERVALDS', -104, ");
 * 
 * builder.append("                          'BINARY', -2, ");
 * builder.append("                          'VARBINARY', -3, ");
 * builder.append("                          'LONGVARBINARY', -4, ");
 * builder.append("                          'ROWID', -8, ");
 * 
 * builder.append("                          'REF CURSOR', -10, ");
 * builder.append("                          'BLOB', 2004, ");
 * builder.append("                          'CLOB', 2005, ");
 * builder.append("                          'BFILE', -13, ");
 * builder.append("                          'STRUCT', 2002, ");
 * builder.append("                          'ARRAY', 2003, ");
 * builder.append("                          'REF', 2006, ");
 * builder.append("                          'OPAQUE', 2007, ");
 * builder.append("                          'JAVA_STRUCT', 2008, ");
 * builder.append("                          'JAVA_OBJECT', 2000, ");
 * builder.append("                          'PLSQL_INDEX_TABLE', -14, ");
 * builder.append("                          'NULL', 0, ");
 * builder.append("                          'NUMBER', 2, ");
 * builder.append("                          'RAW', -2, ");
 * builder.append("                          'FIXED_CHAR', 999, ");
 * builder.append("                          'DATALINK', 70, ");
 * builder.append("                          'BOOLEAN', 16, ");
 * builder.append("                          'LONG', -1, ");//as LONGVARCHAR);
 * builder.append("                          1111) AS data_type, ");//OTHER:
 * 1111 builder.append("       data_type AS type_name, ");
 * builder.append("       DECODE (data_precision, NULL, data_length, ");
 * builder.
 * append("                               data_precision) AS precision, ");
 * builder.append("       data_length AS length, ");
 * builder.append("       data_scale AS scale, ");
 * builder.append("       10 AS radix, ");
 * builder.append("       1 AS nullable, ");
 * builder.append("       NULL AS remarks, ");
 * builder.append("       sequence, "); builder.append("       overload, ");
 * builder.append("       default_value ");
 * builder.append("  FROM all_arguments "); builder.append(" WHERE "); if
 * (meta.getSchema() != null) { builder.append("   owner=? AND "); } if
 * (meta.getCatalog() != null) { builder.append("   package_name=? AND "); }
 * else { builder.append("   package_name IS NULL AND "); }
 * builder.append("       object_name=? "); builder.append("ORDER BY sequence");
 */